//Copyright (c) 2007-2012 Tacke Consulting, Inc

//Permission is hereby granted, free of charge, to any person obtaining a 
//copy of this software and associated documentation files (the "Software"), 
//to deal in the Software without restriction, including without limitation 
//the rights to use, copy, modify, merge, publish, distribute, sublicense, 
//and/or sell copies of the Software, and to permit persons to whom the 
//Software is furnished to do so, subject to the following conditions:

//The above copyright notice and this permission notice shall be included 
//in all copies or substantial portions of the Software.

//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 
//OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 
//FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 
//THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 
//LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 
//FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
//DEALINGS IN THE SOFTWARE. 

using System;
using System.Collections.Generic;
using System.Text;

namespace OpenNETCF.Media.MP3
{
    public sealed class SynchSafeInteger
    {
        private byte[] m_rawdata = new byte[4];

        public static explicit operator int(SynchSafeInteger ssi)
        {
            byte[] buffer = new byte[4];

            // first shift in all bytes, keeping it in network (MSB) order
            buffer[3] = ssi.m_rawdata[3];
            buffer[3] |= (byte)(ssi.m_rawdata[2] << 7);

            buffer[2] = (byte)(ssi.m_rawdata[2] >> 1);
            buffer[2] |= (byte)(ssi.m_rawdata[1] << 6);

            buffer[1] = (byte)(ssi.m_rawdata[1] >> 2);
            buffer[1] |= (byte)(ssi.m_rawdata[0] << 5);

            buffer[0] = (byte)(ssi.m_rawdata[0] >> 3);

            // swap to LSB
            byte[] lsb = new byte[4];
            lsb[0] = buffer[3];
            lsb[1] = buffer[2];
            lsb[2] = buffer[1];
            lsb[3] = buffer[0];

            // convert to an int
            return BitConverter.ToInt32(lsb, 0);
        }

        public int ToInt32()
        {
            return (int)this;
        }

        public byte[] GetBytes()
        {
            return m_rawdata;
        }

        /// <summary>
        /// Synchsafe integers are integers that keep its highest bit (bit 7) zeroed, making seven bits
        /// out of eight available. Thus a 32 bit synchsafe integer can store 28 bits of information.
        ///   Example:   
        ///     255 (0b11111111) encoded as a 16 bit synchsafe integer is 383
        ///     (0b00000001 01111111).
        /// </summary>
        /// <remarks>This method assumes the data is in network byte order</remarks>
        /// <param name="data"></param>
        /// <param name="offset"></param>
        public SynchSafeInteger(byte[] data, int offset)
        {
            Buffer.BlockCopy(data, offset, m_rawdata, 0, 4);
        }

        public SynchSafeInteger(int number)
        {
            byte[] lsb = BitConverter.GetBytes(number);

            m_rawdata[3] = (byte)(lsb[0] & 0x7F);
            m_rawdata[2] = (byte)(((lsb[1] & 0x3F) << 1) | (lsb[0] >> 7));
            m_rawdata[1] = (byte)(((lsb[2] & 0x1F) << 2) | (lsb[1] >> 6));
            m_rawdata[0] = (byte)(((lsb[3] & 0x0F) << 3) | (lsb[2] >> 5));
        }
    }
}
